#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   user.py
@Time    :   2024-07-09 12:55:18
@Author  :   chakcy 
@Email   :   947105045@qq.com
@description   :   user service
'''

import os
import shutil
from typing import Dict, Any, Union

from fastapi.responses import JSONResponse
from fastapi import Request
from fastapi import UploadFile

from ..models.user import UserLoginIn, AddUserIn, UpdateUserIn, UpdatePasswordIn
from ..models import create_response
from ..dao import UserDao
from ..dependencies.jwt import create_access_token, decode_token
from ..utils import check_login_status
from ..utils.user import merge_user_data, set_token, delete_token
from ..utils.encryption import verify_password
from ..config import config

nginx_config = config.nginx

class UserService:
    """
    用户服务

    方法:
    - login: 用户登录
    - register: 用户注册
    - getUserInfo: 获取用户信息
    - logout: 用户退出
    - update_user_info: 更新用户信息
    - update_user_password: 更新用户密码
    """
    @classmethod
    async def login(cls, 
                    user_login: UserLoginIn,
                    redis) ->  Union[JSONResponse, Dict[str, Any]]:
        """
        用户登录
        
        参数：
        - user_login: 用户登录信息
        - redis: redis依赖

        返回值：
        - Dict[str, Any]: 登录成功返回token，失败返回错误信息
        """
        res = await UserDao.getUserByName(user_login.userAccount)
        if not res.result:
            return create_response(data={}, code=400, message="用户不存在")
        user, user_personal = res.data
        if not verify_password(user_login.userPassword, user.userPassword):
            return create_response(data={}, code=400, message="密码错误")
        res = merge_user_data(user, user_personal)
        token = create_access_token(data=res)
        print(decode_token(token))
        return await set_token(token, res["userAccountId"], "登录成功", redis)

    @classmethod
    async def register(cls, add_user: AddUserIn) -> Dict[str, Any]:
        """
        用户注册
        
        参数：
        - add_user: 用户注册信息

        返回值：
        - Dict[str, Any]: 注册成功返回用户信息，失败返回错误信息
        """
        user = await UserDao.getUserByName(add_user.userAccount)
        if user.result:
            return create_response(data={}, code=400, message="用户已存在")
        res = await UserDao.addUser(add_user)
        if not res.result:
            return create_response(data={}, code=400, message=res.message)
        user_item = AddUserIn.model_validate(add_user).model_dump()
        del user_item["userPassword"]
        del user_item["chackPassword"]
        return create_response(data=user_item, code=200, message="注册成功")
    
    @staticmethod
    @check_login_status
    async def getUserInfo(request: Request,
                          redis) -> Dict[str, Any]:
        """
        获取用户信息
        
        参数：
        - data: 用户信息
        - redis: redis依赖

        返回值：
        - Dict[str, Any]: 用户信息
        """
        return create_response(data=request.state.data, code=200, message="获取成功")

    @classmethod
    async def logout(cls,
                     data,
                     redis) -> Dict[str, Any]:
        """
        用户退出
        
        参数：
        - data: 用户信息
        - redis: redis依赖

        返回值：
        - Dict[str, Any]: 退出成功
        """
        return await delete_token(data["userAccountId"], redis)
    
    @staticmethod
    @check_login_status
    async def update_user_info(request: Request,
                               redis,
                               user: UpdateUserIn) -> Union[JSONResponse, Dict[str, Any]]:
        """
        更新用户信息

        参数：
        - data: 用户信息
        - redis: redis依赖
        - user: 更新用户信息

        返回值：
        - Dict[str, Any]: 更新成功或失败
        """
        res = await UserDao.updateUser(request.state.data.get("userAccountId"), user)
        if res.result:
            user_item, user_personal_item = res.data
            result = merge_user_data(user_item, user_personal_item)
            print(res)
            token = create_access_token(data=result)
            return await set_token(token, result["userAccountId"], res.message, redis)
        else:
            return create_response(data={}, message=res.message, code=500)
        
    @staticmethod
    @check_login_status
    async def update_user_password(request: Request,
                                   redis,
                                   passwordIn: UpdatePasswordIn) -> Dict[str, Any]:
        """
        更新用户密码

        参数：
        - data: 用户信息
        - redis: redis依赖
        - passwordIn: 更新密码信息

        返回值：
        - Dict[str, Any]: 更新成功或失败
        """
        data = request.state.data
        user_id = data["userAccountId"]
        if passwordIn.checkNewPassword != passwordIn.newPassword:
            return create_response(data={}, message="两次输入的密码不一致", code=400)
        res = await UserDao.updateUserPassword(user_id ,passwordIn)

        if res.result:
            return create_response(data={}, message=res.message, code=200)
        else:
            return create_response(data={}, message=res.message, code=500)
        
    @staticmethod
    @check_login_status
    async def uploader_avatar(request: Request,
                              redis,
                              file: UploadFile) -> Dict[str, Any]:
        """
        更新用户头像

        参数：
        - data: 用户信息
        - redis: redis依赖
        - file: 头像文件

        返回值：
        - Dict[str, Any]: 更新成功或失败
        """
        file_path = f".{config.upload_folder}/avatar/{request.state.data['userAccountId']}.jpg"
        # 判断 /uploads/avatar/ 目录是否存在，不存在则创建
        if not os.path.exists(os.path.dirname(file_path)):
            os.makedirs(os.path.dirname(file_path))

        with open(file_path, "wb") as buffer:
            shutil.copyfileobj(file.file, buffer)

        avatar = f"http://{nginx_config.server_name}:{nginx_config.server_port}/static/avatar/{request.state.data['userAccountId']}.jpg"

        await UserDao.updateUserAvatar(request.state.data["userAccountId"], avatar)

        return create_response(data={}, message="上传成功", code=200)
    